﻿using System;
using System.Runtime.Serialization;
using log4net;
using OdsServer.Common.Packet;
using OdsServer.Common.Utils;

namespace OdsServer.Common.DataTransfer
{
    public static class PacketFactory
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(PacketFactory));

        public static PacketHeader ExtractHeader(byte[] source)
        {
            unsafe
            {
                int headerSize  = sizeof(PacketHeader);
                byte[] header   = new byte[headerSize];

                Buffer.BlockCopy(source, 0, header, 0, headerSize);

                return DataTransferUtils.RawDeserialize<PacketHeader>(header);
            }
        }

        public static IBasePacket DeserializePacket(byte[] source)
        {
            PacketHeader ph = ExtractHeader(source);
            byte[] body     = new byte[ph.lenght];

            Buffer.BlockCopy(source, 0, body, 0, body.Length);

            return TransformPacket(ref body, ph);
        }

        public static IBasePacket TransformPacket(ref byte[] source, PacketHeader header)
        {
            IBasePacket result = null;

            try
            {
                switch (header.type)
                {
                    case PacketType.SingleChannelDataPacket:
                        result = (IBasePacket)DataTransferUtils.RawDeserialize<SingleChannelDataPacket>(source);
                        break;
                    case PacketType.MessagePacket:
                        result = (IBasePacket)DataTransferUtils.RawDeserialize<MessagePacket>(source);
                        break;
                    case PacketType.CommandPacket:
                        result = (IBasePacket)DataTransferUtils.RawDeserialize<CommandPacket>(source);
                        break;
                    case PacketType.MultiChannelDataPacket:
                        result = (IBasePacket)DataTransferUtils.RawDeserialize<MultiChannel8DataPacket>(source);
                        break;
                    default:
                        log.WarnFormat(
                                "Factory cannot construct unknown packet type: {0}",
                                header.type );
                        break;
                }
            }
            catch (Exception)
            {
                throw new SerializationException(
                        string.Format("Error transforming packet of type: {0}", header.type.ToString()) );
            }

            return result;
        }
    }
}